//Stephen Kirksharian
//Robert Harkreader
//CPSC 321
//DUE 4/27/08

// Texas A&M University          //
// cpsc321 Computer Architecture //
// $Id: IdealMemory.v,v 1.3 2002/11/19 00:58:22 miket Exp miket $ //

// InstrMem is an asynchronous read memory model //
// MemSize Wordise parameterize the memory module at instantiation time //
module InstrMem (Mem_Addr, Dout);

   parameter T_rd = 30;
   parameter MemSize = 1024, WordSize = 32;
   
   input  [WordSize-1:0] Mem_Addr;
   output [WordSize-1:0] Dout;
   reg [WordSize-1:0] Dout;
   
   reg [WordSize-1:0] 	 Mem[0:MemSize-1];   // register array (SRAM) 
   
   `include "imeminit.v"
always
      #T_rd  Dout = Mem[ Mem_Addr >> 2 ];
endmodule // Imem

// DataMem is an asynchronous read, synchronous write memory model //
// This memory cannot be read and written to simultaneously        //
// mem_wr and mem_rd signals are the same

module DataMem (Mem_Addr, CLK, Mem_rd, Mem_wr, Mem_b_w,Mem_DIN, Mem_DOUT);

   parameter T_rd = 30, T_wr = 30;
   parameter MemSize = 1024, WordSize = 32;

   input [WordSize-1:0] Mem_Addr;
   input 		CLK, Mem_rd, Mem_wr,Mem_b_w;
   input [WordSize-1:0] Mem_DIN;
   output [WordSize-1:0] Mem_DOUT;
   reg [WordSize-1:0] 	 Mem_DOUT;
   
   reg [WordSize-1:0] 	 Mem[0:MemSize-1];
   reg [31:0]		 temp,tempOut;
   integer 		 i;
   
   `include "dmeminit.v"
      
   always @( Mem_b_w or Mem_Addr or Mem_rd ) begin
	 temp <= Mem[Mem_Addr>>2];
	 if ( ~Mem_wr && Mem_rd && ~Mem_b_w)
	    Mem_DOUT <=#T_rd   Mem[Mem_Addr >> 2];
	 else if(~Mem_wr && Mem_rd && Mem_b_w) begin
	  $display("Addr[1:0]: %b\t temp=%d",Mem_Addr[1:0],temp);
	  case(Mem_Addr[1:0])
	    2'b00: Mem_DOUT<=#T_rd {24'd0,temp[7:0]};
	    2'b01: Mem_DOUT<=#T_rd {24'd0,temp[15:8]};
	    2'b10: Mem_DOUT<=#T_rd {24'd0,temp[23:16]};
	    2'b11: Mem_DOUT<=#T_rd {24'd0,temp[31:24]};
	  endcase
	 end
 	
end

   always @(Mem_DOUT) begin
	$display($time, " 	outputing MemDOUT: %d",Mem_DOUT);
  	$display($time, " 	from Address: %d",Mem_Addr>>2);
   end
   always @(negedge CLK)
     if (Mem_wr == 1)
	 begin
	    $display ($time, " Writing:%d\tTo Address: %d", Mem_DIN,Mem_Addr>>2);
	    if(Mem_b_w) begin
	      tempOut=Mem[Mem_Addr>>2];
	      case(Mem_Addr[1:0])
		2'b00:tempOut[7:0] <=Mem_DIN;
		2'b01:tempOut[15:8]<=Mem_DIN;
	 	2'b10:tempOut[23:16]<=Mem_DIN;
		2'b11:tempOut[31:24]<=Mem_DIN; 
	      endcase
		Mem[Mem_Addr>>2]<=#T_wr tempOut;
	    end else begin 
	    Mem[Mem_Addr >> 2] <= #T_wr Mem_DIN;
	    end 
	end

   
endmodule // Dmem
